<script setup lang="ts">
import { ref, computed, nextTick, type PropType } from "vue"
import { createCertificateInfoApi, updateCertificateInfoApi, getCourseDirectory } from "#/api/certificate/list"
import { certificateType } from '../const'
import { questionTypeOptions } from "#/views/manage/modules/const"
import { $t } from "@vben/locales"
import { Play } from '@vben/icons';
import { cloneDeep } from '@vben/utils';
import { isValidJSON } from "#/utils/isValidJSON"
import { Info } from '@vben/icons';
import ImageUpload from '#/components/common/image-upload.vue';
import { ElMessage, type CheckboxValueType, type FormInstance } from 'element-plus'
import { trimStringParams } from '#/utils/trimStringParams'

defineOptions({ name: 'Dialog' })

interface ClassNode {
  id: string,
  name: string,
  courseId: string,
  isOpen: boolean,
  checkedTypes: [],
  checkAll: boolean,
  isIndeterminate: boolean,
  questionTypeList: Array<{
    value: string,
    label: string,
    selected: boolean,
    number: void,
    score: void,
    ispartScore?: boolean,
    partScore?: number | null
  }>
}
interface CourseInfo {
  id: string
  name: string
}

const props = defineProps({
  courseInfoList: {
    type: Array as PropType<CourseInfo[]>,
    default: () => [],
  }
})
const emit = defineEmits(['queryTable'])
const nodeLoading = ref(false)
const submitLoading = ref(false)
const dialogVisible = ref(false)
const title = ref()
const detailPreview = ref(false)
const editData = ref()
const defaultFrom = {
  name: '',
  description: '',
  type: null,
  courseId: null,
  passScore: null,
  targetPrice: null as number | null,
  discountPrice: null as number | null,
  certificateImage: '',
  classNodes: [] as ClassNode[]
}
const formRef = ref<FormInstance>()
const imageUploadRef = ref<InstanceType<typeof ImageUpload>>()
const formInline = ref(cloneDeep(defaultFrom))
const rules = {
  name: [{ required: true, message: $t('common.inputPhTxt', [$t('whiteLink.certifiedNameTxt')]), trigger: 'blur' }],
  type: [{ required: true, message: $t('common.selectPhTxt', [$t('whiteLink.certifiedTypeTxt')]), trigger: 'change' }],
  certificateImage: [{ required: true, message: $t('common.selectPhTxt', ['图片']), trigger: 'change' }],
  courseId: [{ /*required: true,**/ message: $t('common.selectPhTxt', [$t('whiteLink.courseTxt')]), trigger: 'change' }],
  passScore: [{ /*required: true,**/ message: $t('common.inputPhTxt', [$t('whiteLink.passScoreTxt')]), trigger: 'blur' }],
  number: [{ required: true, message: $t('common.inputPhTxt', [$t('whiteLink.questionNumberTxt')]), trigger: 'blur' }],
  // score: [{ required: true, message: $t('common.inputPhTxt', [$t('whiteLink.questionScoreTxt')]), trigger: 'blur' }],
  score: [{
    required: true,
    validator: (rule: any, value: any, callback: any) => {
      try {
        // 获取当前校验的字段路径
        const fieldPath = rule.field
        const pathParts = fieldPath.split('.')
        const sIdx = parseInt(pathParts[1]) // classNodes.${sIdx}.questionTypeList.${index}.partScore
        const qIdx = parseInt(pathParts[3])

        const questionType = formInline.value.classNodes[sIdx]?.questionTypeList[qIdx]
        if (!value) {
          callback(new Error($t('common.inputPhTxt', [$t('whiteLink.questionScoreTxt')])))
        } else if (questionType?.value === 'checkbox') {
          if (questionType?.ispartScore) {
            if (!questionType?.partScore) {
              callback(new Error($t('common.inputPhTxt', [$t('whiteLink.partScoreTxt')])))
            } else if (questionType?.partScore >= value) {
              callback(new Error($t('whiteLink.partScoreTipTxt')))
            } else {
              callback()
            }
          } else {
            callback()
          }
        } else {
          callback()
        }
      } catch (error) {
        callback()
      }
    },
    trigger: 'blur'
  }]
}

//计算分数/
const getTotal = computed(() => {
  return (formInline.value.classNodes || []).reduce((sum, node) => {
    return sum + (node.questionTypeList || []).reduce((subSum, q) => {
      return subSum + (Number(q.score) || 0) * (Number(q.number) || 0)
    }, 0)
  }, 0)
})

const sectionScore = computed(() => {
  return (node: ClassNode) => {
    const score = node.questionTypeList.reduce((a, b: { score: any, number: any }) => +(b?.score * b?.number || 0) + a, 0)
    return score;
  }
})

// 全选
const handleCheckAllChange = (val: CheckboxValueType, section: ClassNode) => {
  console.log(val)
  section.checkedTypes = val ? questionTypeOptions.map(item => item.value) as any : []
  section.isIndeterminate = false
  updateQTList(section)
}

// 单选更新
const questionTypeUpdate = (value: CheckboxValueType[], section: ClassNode) => {
  const checkedCount = value.length
  section.checkAll = checkedCount === questionTypeOptions.length
  section.isIndeterminate = checkedCount > 0 && checkedCount < questionTypeOptions.length
  updateQTList(section)
}

// 更新展示输入题数/分数
const updateQTList = (node: ClassNode) => {
  console.log(node)
  node.questionTypeList.forEach((_: any) => {
    const selected = node.checkedTypes.find(v => v === _?.value)
    _.selected = !!selected
    if (!selected) {
      _.number = null
      _.score = null
      _.ispartScore = false
      _.partScore = null
    }
  })
}

const handleClose = () => {
  console.log(defaultFrom)
  formInline.value = cloneDeep(defaultFrom)
  dialogVisible.value = false
  formRef.value?.resetFields()
}

const toggleSection = (node: ClassNode) => {
  node.isOpen = !node.isOpen
}
const courseIdUpdate = (id: any) => {
  if (id) {
    nodeLoading.value = true
    getCourseDirectory({ courseId: id }).then(res => {
      if (res) {
        formInline.value.classNodes = res.map((item: any) => {
          const { id = '', courseId = '', name = '' } = item
          return {
            id,
            courseId,
            name,
            questionTypeList: questionTypeOptions.map(v => {
              return {
                ...v,
                selected: false,
                number: null,
                score: null,
                ispartScore: false,
                partScore: null
              }
            })
          }
        })
      }
    }).finally(() => {
      nodeLoading.value = false
    })
  } else {
    formInline.value.classNodes = []
  }
}
const inint = (data: any = null, titleStr: any) => {
  title.value = titleStr
  detailPreview.value = titleStr === $t('common.detailTxt')
  editData.value = data
  if (data) {
    const { name, description, questionType, passScore, type, courseId, targetPrice, discountPrice, certificateImage } = data
    let typeList = null
    try {
      typeList = JSON.parse(questionType) || []
    } catch { }
    const nodes = typeList.map((item: any) => {
      const { chapterId: id, chapterName: name, examPapersTypes: list = [] } = item
      const selectedAll = list.length === questionTypeOptions.length
      const checkedTypes = list.map((ql: { number: any, score: any, type: any }) => ql?.type) || []
      return {
        id,
        courseId,
        name,
        isOpen: false,
        checkedTypes,
        checkAll: selectedAll,
        isIndeterminate: !selectedAll,
        questionTypeList: questionTypeOptions.map(v => {
          const ql = list.find((_: { number: any, score: any, type: any }) => _?.type === v?.value)
          return {
            ...v,
            selected: !!ql,
            number: ql?.number ?? null,
            score: ql?.score ?? null,
            ispartScore: ql?.specialRule && isValidJSON(ql?.specialRule) ? !!JSON.parse(ql?.specialRule)?.partScore : false,
            partScore: ql?.specialRule && isValidJSON(ql?.specialRule) ? JSON.parse(ql?.specialRule)?.partScore : null
          }
        })
      }
    })
    formInline.value = {
      name,
      description,
      classNodes: nodes,
      passScore,
      type,
      courseId,
      targetPrice: targetPrice ? Number(targetPrice) : null,
      discountPrice: discountPrice ? Number(discountPrice) : null,
      certificateImage
    }
    nextTick(() => {
      imageUploadRef.value?.initImageData(certificateImage)
    })
  }
  dialogVisible.value = true

}
const handleNumberBlur = (i: any) => {
  console.log(i.number)
  if (i.number < 0) {
    i.number = null
  }
}
const handleScoreBlur = (i: any) => {
  if (i.score < 0) {
    i.score = null
  }
}
const handlePartScoreChange = (i: any) => {
  if (!i.ispartScore) {
    i.partScore = null
  }
}
const submit = () => {
  if (!formRef) return
  formRef.value?.validate(async (valid: any, fields: any) => {
    if (valid) {
      await imageUploadRef.value?.uploadToObs();
      const { description, name, passScore, type, classNodes, courseId = '', targetPrice, certificateImage, discountPrice } = formInline.value
      const params = {
        description: description,
        name,
        passScore,
        courseId,
        type,
        targetPrice,
        discountPrice,
        certificateImage,
        courseChapterExamPapersTypes: classNodes.length > 0 ? classNodes.map((item: ClassNode) => {
          const { id, name, questionTypeList } = item
          return {
            chapterId: id,
            chapterName: name,
            examPapersTypes: questionTypeList?.filter((_: { selected: any }) => _.selected).map((_: any) => {
              return {
                type: _.value,
                number: _.number,
                score: _.score,
                specialRule: _.ispartScore ? JSON.stringify({
                  partScore: _.partScore
                }) : ''
              }
            })
          }
        }) : []
      } as any
      if (title.value === $t('common.editTxt')) {
        params['id'] = editData.value.id
      }
      submitLoading.value = true
      const API = title.value === $t('common.newTxt') ? createCertificateInfoApi(trimStringParams(params)) : updateCertificateInfoApi(trimStringParams(params))
      API.then(() => {
        ElMessage.success($t('common.handleTxt', [$t('common.successTxt')]))
        handleClose()
        dialogVisible.value = false
        emit('queryTable')
      }).finally(() => {
        submitLoading.value = false
      })
    } else {
      // 校验失败时，自动展开包含错误项的章节并定位到第一个错误项
      handleValidationError(fields)
    }
  })
}

// 处理校验错误，自动展开包含错误项的所有章节并定位到第一个错误项
const handleValidationError = (fields: any) => {
  if (!fields) return

  // 先关闭所有章节
  formInline.value.classNodes.forEach((section: ClassNode) => {
    section.isOpen = false
  })

  // 找到所有错误字段
  const errorFields = Object.keys(fields)
  if (errorFields.length === 0) return

  // 收集需要展开的章节索引
  const sectionsToOpen = new Set<number>()
  let firstErrorField = ''

  errorFields.forEach((field) => {
    // 解析字段路径，格式如：classNodes.0.questionTypeList.1.number
    const fieldPath = field.split('.')

    // 如果是章节内的字段
    if (fieldPath[0] === 'classNodes' && fieldPath.length >= 4) {
      const sectionIndex = parseInt(fieldPath[1] || '0')
      sectionsToOpen.add(sectionIndex)

      // 记录第一个错误字段用于定位
      if (!firstErrorField) {
        firstErrorField = field
      }
    } else {
      // 如果是非章节内的字段（如name, courseId, type, passScore等）
      if (!firstErrorField) {
        firstErrorField = field
      }
    }
  })

  // 展开所有包含错误项的章节
  sectionsToOpen.forEach((sectionIndex) => {
    const section = formInline.value.classNodes[sectionIndex]
    if (section) {
      section.isOpen = true
    }
  })

  // 等待DOM更新后滚动到第一个错误项
  if (firstErrorField) {
    nextTick(() => {
      // 查找错误字段对应的DOM元素
      let errorElement = document.querySelector(`[data-field="${firstErrorField}"]`)

      // 如果没有找到data-field，尝试通过prop属性查找
      if (!errorElement) {
        errorElement = document.querySelector(`[prop="${firstErrorField}"]`)
      }

      if (errorElement) {
        // 滚动到错误元素
        errorElement.scrollIntoView({
          behavior: 'smooth',
          block: 'center'
        })

        // 添加高亮效果
        errorElement.classList.add('error-highlight')
        setTimeout(() => {
          errorElement.classList.remove('error-highlight')
        }, 2000)
      }
    })
  }
}
const handleCertificateImageUpdate = (value: any) => {
  console.log(value, 123456)
  formInline.value.certificateImage = value
  formRef.value?.validateField('certificateImage')
}

defineExpose({ inint })

</script>
<template>
  <el-drawer :destroy-on-close="true" :close-on-click-modal="false" @close="handleClose" :close-on-press-escape="false"
    :append-to-body="true" class="detail-war" size="80%" v-model="dialogVisible" direction="rtl">
    <template #header>
      <h4 class="detail-title text-black font-bold">{{ title }}</h4>
    </template>
    <template #default>
      <div>
        <el-form ref="formRef" :inline="true" label-width="110px" :rules="rules" :model="formInline"
          label-position="right" class="h-auto overflow-scroll">
          <el-form-item :label="$t('whiteLink.certifiedNameTxt')" prop="name" class="w-[50%]" :data-field="'name'">
            <div v-if="detailPreview">{{ formInline.name }}</div>
            <el-input clearable v-else type="text" style="width: 100%" :maxlength="50" v-model="formInline.name"
              :placeholder="$t('common.inputPhTxt', [$t('whiteLink.certifiedNameTxt')])" />
          </el-form-item>
          <el-form-item :label="$t('whiteLink.requiredCourseTxt')" prop="courseId" class="w-[50%]"
            :data-field="'courseId'">
            <div v-if="detailPreview">{{props.courseInfoList.find?.((_: any) => _.id === formInline.courseId)?.name ??
              '--'}}</div>
            <el-select v-else @change="courseIdUpdate" :fit-input-width="true" clearable v-model="formInline.courseId"
              :placeholder="$t('common.selectPhTxt', [$t('whiteLink.requiredCourseTxt')])">
              <el-option v-for="item in props.courseInfoList as any" :key="item.id" :label="item.name"
                :value="item.id" />
            </el-select>
          </el-form-item>
          <el-form-item :label="$t('whiteLink.certifiedTypeTxt')" prop="type" class="w-[50%]" :data-field="'type'">
            <div v-if="detailPreview">{{certificateType.find((_: any) => _?.type === formInline.type)?.name ?? '--'}}
            </div>
            <el-select v-else clearable :fit-input-width="true" v-model="formInline.type"
              :placeholder="$t('common.selectPhTxt', [$t('whiteLink.certifiedTypeTxt')])">
              <el-option v-for="item in certificateType" :key="item.type" :label="item.name" :value="item.type" />
            </el-select>
          </el-form-item>
          <el-form-item :label="$t('whiteLink.passScoreTxt')" prop="passScore" class="w-[50%]"
            :data-field="'passScore'">
            <div v-if="detailPreview">{{ formInline.passScore }}</div>
            <el-input @wheel.prevent v-else type="number" style="width: 100%" :maxlength="200"
              v-model="formInline.passScore" :placeholder="$t('common.inputPhTxt', [$t('whiteLink.passScoreTxt')])" />
          </el-form-item>
          <el-form-item :label="$t('whiteLink.targetPriceTxt')" prop="targetPrice" class="w-[50%]"
            :data-field="'targetPrice'">
            <div v-if="detailPreview">{{ formInline.targetPrice }}</div>
            <el-input-number @wheel.prevent v-else type="number" style="width: 100%" :max="100000" :min="0"
              :precision="2" :controls="false" v-model="formInline.targetPrice"
              :placeholder="$t('common.inputPhTxt', [$t('whiteLink.priceTipTxt')])" />
          </el-form-item>
          <el-form-item :label="$t('whiteLink.discountPriceTxt')" prop="discountPrice" class="w-[50%]"
            :data-field="'discountPrice'">
            <div v-if="detailPreview">{{ formInline.discountPrice }}</div>
            <el-input-number v-else style="width: 100%" :max="100000" :min="0" :precision="2" :controls="false"
              v-model="formInline.discountPrice"
              :placeholder="$t('common.inputPhTxt', [$t('whiteLink.priceTipTxt')])" />
          </el-form-item>
          <el-form-item label="图片" class="w-[100%]" prop="certificateImage">
            <ImageUpload ref="imageUploadRef" @update:modelValue="handleCertificateImageUpdate" width="200px"
              height="112px" :maxSize="5" :showDelete="true" />
          </el-form-item>
          <el-form-item :label="$t('whiteLink.certifiedDescTxt')" class="w-[100%]">
            <div v-if="detailPreview">{{ formInline.description || '--' }}</div>
            <el-input v-else type="textarea" :maxlength="500" show-word-limit v-model="formInline.description"
              :placeholder="$t('common.inputPhTxt', [$t('whiteLink.certifiedDescTxt')])" />
          </el-form-item>
          <el-form-item class="w-[100%] mb-[0px]" v-loading="nodeLoading">
            <div v-for="(section, sIdx) in formInline.classNodes" :key="section.id"
              class="w-[100%] pb-[15px] overflow-hidden">
              <div
                class="w-[100%] flex justify-between leading-[40px] px-[10px] py-[4px] rounded-[8px] mb-[5px] bg-[#F2F7FD] cursor-pointer"
                @click="toggleSection(section)">
                <div class="flex-auto flex items-center">
                  <Play fill="#595959" class="text-[#595959] play-icon scale-[0.6] inline-block align-top"
                    :class="[section.isOpen ? 'isOpen' : 'isClose']"></Play>
                  <span class="font-[500] text-[14px]">{{ section?.name || '--' }}</span>
                </div>
                <div class="flex-none w-[100px] flex items-center text-[14px]">
                  <span class="text-[#595959]">{{ $t('common.totalScoreTxt') }}</span>
                  <span class="text-[#191919] ml-[10px]">{{ sectionScore(section) ?? '--' }}</span>
                </div>
              </div>
              <transition>
                <div class="qTSetting" :class="[section.isOpen ? 'isOpen' : 'isClose']">
                  <!-- required -->
                  <el-form-item v-show="section.isOpen" :label="$t('whiteLink.questionTypeSettingTxt')"
                    class="w-[100%]">
                    <!-- checkout校验 :prop="`classNodes.${sIdx}.checkedTypes`" :rules="rules.checkedTypes" -->
                    <el-form-item>
                      <el-checkbox :disabled="detailPreview" style="margin-right:30px" v-model="section.checkAll"
                        :indeterminate="section.isIndeterminate"
                        @change="(val: CheckboxValueType) => handleCheckAllChange(val, section)">
                        {{ $t('common.selectAllTxt') }}
                      </el-checkbox>
                      <el-checkbox-group :disabled="detailPreview" v-model="section.checkedTypes"
                        @change="(val: CheckboxValueType[]) => questionTypeUpdate(val, section)">
                        <el-checkbox v-for="item in section.questionTypeList" :key="item.value" :label="item.label"
                          :value="item.value">
                          {{ item.label }}
                        </el-checkbox>
                      </el-checkbox-group>
                    </el-form-item>
                    <div class="w-full mt-[5px]">
                      <div v-for="(i, index) in section.questionTypeList" :key="index" class="q-type-war">
                        <div class="q-type flex items-start" v-if="i.selected">
                          <span class="mr-[10px] w-[50px] text-[#595959]">{{ i.label }}</span>
                          <!-- 题目数量校验 :prop="`classNodes.${sIdx}.questionTypeList.${index}.number`"
                          :rules="rules.number" -->
                          <el-form-item :prop="`classNodes.${sIdx}.questionTypeList.${index}.number`"
                            :rules="rules.number" class="w-[50%] pr-[50px]"
                            :data-field="`classNodes.${sIdx}.questionTypeList.${index}.number`">
                            <el-input @wheel.prevent :readonly="detailPreview" type="number" :min="0"
                              @blur="handleNumberBlur(i)" maxlength="10" style="width: 100%" v-model="i.number"
                              :placeholder="$t('common.inputPhTxt', [$t('whiteLink.questionNumberTxt')])">
                              <template #prepend>{{ $t('whiteLink.questionNumberTxt') }}</template>
                            </el-input>
                          </el-form-item>
                          <!-- 每题分数检验 :prop="`classNodes.${sIdx}.questionTypeList.${index}.score`" :rules="rules.score" -->
                          <el-form-item :prop="`classNodes.${sIdx}.questionTypeList.${index}.score`"
                            :rules="rules.score" class="w-[50%]"
                            :data-field="`classNodes.${sIdx}.questionTypeList.${index}.score`">
                            <div class="w-[100%]">
                              <el-input @wheel.prevent :readonly="detailPreview" type="number" :min="0"
                                @blur="handleScoreBlur(i)" style="width: 100%" v-model="i.score" maxlength="10"
                                :placeholder="$t('common.inputPhTxt', [$t('whiteLink.questionScoreTxt')])">
                                <template #prepend>{{ $t('whiteLink.questionScoreTxt') }}</template>
                              </el-input>
                              <div v-if="i.value === 'checkbox'"
                                class="w-[100%] flex items-center justify-start text-right mt-[10px]">
                                <el-checkbox v-model="i.ispartScore" @change="handlePartScoreChange(i)"></el-checkbox>
                                <span class="text-[#191919] ml-[5px] mr-[5px]">{{ $t('whiteLink.getPartScoreTxt')
                                }}</span>
                                <el-input-number :controls="false" v-model="i.partScore" :disabled="!i.ispartScore"
                                  :min="0" :max="+i.score" style="width: 80px" :placeholder="$t('common.inputPhTxt')" maxlength="10">
                                </el-input-number>
                                <span class="text-[#191919] ml-[5px]">{{ $t('common.gradesTxt') }}</span>
                                <el-tooltip effect="dark" :show-after="1000" placement="top">
                                  <template #content>{{ $t('whiteLink.checkboxPartScoreTipTxt1') }}<br />{{
                                    $t('whiteLink.checkboxPartScoreTipTxt2') }}</template>
                                  <Info class="scale-[.7] cursor-pointer" />
                                </el-tooltip>
                              </div>
                            </div>
                          </el-form-item>
                        </div>
                      </div>
                    </div>
                  </el-form-item>
                </div>
              </transition>
            </div>
          </el-form-item>
          <el-form-item v-if="formInline.classNodes.length > 0" label="" class="w-[100%]">
            <div class="w-[100%] flex items-center justify-end text-right">
              <span class="text-[#595959]">{{ $t('whiteLink.totalScoreTxt') }}</span>
              <span class="text-[#191919] text-[24px] ml-[5px]">{{ getTotal }}</span>
            </div>
          </el-form-item>
        </el-form>
      </div>
    </template>
    <template #footer>
      <div class="dialog-footer">
        <el-button v-show="detailPreview" type="primary" @click="handleClose">
          {{ $t('common.closeTxt') }}
        </el-button>
        <el-button v-show="!detailPreview" @click="handleClose">
          {{ $t('common.cancelTxt') }}
        </el-button>
        <el-button v-show="!detailPreview" type="primary" @click="submit" :loading="submitLoading">
          {{ $t('common.submitTxt') }}
        </el-button>
      </div>
    </template>
  </el-drawer>
</template>
<style lang="less" scoped>
.hide-upload-btn :deep(.el-upload--picture-card) {
  display: none !important;
}

:deep(.el-form--inline .el-form-item) {
  margin-right: 0px;
}

:deep(.el-form-item) {
  &:last-of-type {
    margin-bottom: 0px;
  }
}

:deep(.el-input-number .el-input__inner) {
  text-align: left;
}

:deep(.el-checkbox__label) {
  font-weight: normal;
}

.play-icon.isClose {
  transform: rotate(0deg) scale(0.6);
  transition: transform 0.2s;
}

.play-icon.isOpen {
  transform: rotate(90deg) scale(0.6);
  transition: transform 0.2s;
}

.qTSetting {
  max-height: 0px;
}

.qTSetting.isOpen {
  transition: max-height .5s ease-in-out;
  max-height: 600px;
}

.qTSetting.isClose {
  transition: max-height .5s ease-in-out;
  max-height: 0px;
}

.q-type-war {
  .q-type {
    margin-bottom: 16px;
  }

  &:last-of-type {
    .q-type {
      margin-bottom: 0px;
    }
  }
}
</style>
